<template>
  <view :class="[ns.b, disabled && 'is-disabled']">
    <template v-if="controls">
      <Button v-for="item in [fv.reduceProps, fv.addProps]" :="item.props" :class="[ns.e('controls')]">
        <image mode="heightFix" :src="localFile.getImage('components/numberbox-filler')"></image>
        <view :class="['iconfont', item.iconName]"></view>
      </Button>
    </template>
    <Input :="fv.inputProps">
      <template v-for="slotName in Object.keys($slots)">
        <slot :name="slotName"></slot>
      </template>
    </Input>
  </view>
</template>

<script lang="ts" setup>
import { computed, reactive } from 'vue'
import Numberbox from '.'
import { isEmpty, useNamespace } from '@/utils'
import Button from '@/components/button/index.vue'
import Input from '@/components/input/index.vue'
import { Button as ButtonNamespace } from '@/components'
import localFile from '@/utils/local-file'
import Decimal from 'decimal.js'

defineOptions({
  name: Numberbox.name
})
const props = defineProps(Numberbox.props)
const emits = defineEmits(Numberbox.emits)
const ns = useNamespace(Numberbox.name)
const state = reactive({
  value: String(props.modelValue ?? '') || undefined
})
const fv = computed(() => {
  const addProps = {
    props: <ButtonNamespace.Props>{
      disabled: props.disabled || !isEmpty(props.max) && props.max <= props.modelValue!,
      class: [ns.e('add')],
      onClick: () => clickControls(1),
    },
    iconName: 'icon-jia'
  }
  const reduceProps = {
    props: <ButtonNamespace.Props>{
      disabled: props.disabled || !isEmpty(props.min) && props.min >= props.modelValue!,
      class: [ns.e('reduce')],
      onClick: () => clickControls(-1)
    },
    iconName: 'icon-jian'
  }
  const inputProps: Numberbox.Props['inputProps'] = {
    class: [ns.e('input')],
    modelValue: state.value,
    disabled: props.disabled,
    type: 'number',
    clearable: false,
    ...props.inputProps,
    onBlur: change,
    onChange: val => {
      emits('update:modelValue', +val)
      emits('change', +val) 
      // change(val)
      state.value = val
    },
  }
  return {
    inputProps,
    addProps,
    reduceProps
  }
})

function change(val?: string | number) {
  let value = String(val ?? '') || undefined

  if (value === props.modelValue || props.disabled) return
  if (isEmpty(value)) {
    state.value = value
    emits('update:modelValue', value)
    emits('change', value)
    return value
  }

  let v = +value

  if (props.stepStrictly) {
    const remainder = new Decimal(v).mod(props.step).toNumber() || props.step
    v = new Decimal(props.step).sub(remainder).add(v).toNumber()
  }
  if (!isEmpty(props.min)) {
    let min = props.min
    if (props.stepStrictly) 
      min = new Decimal(min).div(props.step).ceil().mul(props.step).toNumber()
    v = Math.max(min, v)
  }
  if (!isEmpty(props.max)) {
    let max = props.max
    if (props.stepStrictly) 
      max = new Decimal(max).div(props.step).floor().mul(props.step).toNumber()
    v = Math.min(max, v)
  }
  if (!isEmpty(props.precision)) {
    const dot = '.'
    const [ingeter, decimal = ''] = String(v).split(dot)

    state.value = ingeter + dot
      + decimal.slice(0, props.precision).padEnd(props.precision, '0')
    v = +state.value
  } else {
    state.value = v + ''
  }

  emits('update:modelValue', v)
  emits('change', v)
  return v
}
function clickControls(val: number){
  const step = new Decimal(props.step).mul(val)
  const isAdd = val > 0
  const emitName = isAdd ? 'add' : 'reduce'
  const value = change(new Decimal(+props.modelValue! || 0).add(step).toNumber())
  
  emits(emitName as any, value)
}
</script>